// 4、理解了依赖与数据劫持的两大核心概念，
// 现在可以动手尝试将前面的部分组装起来，
// 实现简单的响应式函数方法了。

import { log } from "./shared";

// ----->这是来自模块2的部分
const targetMap = new WeakMap(); // 全局映射：响应式对象--->属性依赖集合
function track(
  targetMap: TargetMap,
  target: any,
  key: string | number | symbol
) {
  let depMap = targetMap.get(target); // 哈希表(集合)： 属性--->依赖队列
  if (!depMap) {
    depMap = new Map();
    targetMap.set(target, depMap);
  }
  let dep = depMap.get(key); // 依赖队列
  if (!dep) {
    dep = new Set();
    depMap.set(key, dep);
  }
  dep.add(effect); // 添加进需要依赖的函数，源码中为effect
}
function trigger(targetMap: TargetMap, target: any, key: string | number) {
  const depMap = targetMap.get(target);
  if (!depMap) return; // 对象不存在依赖集合就直接返回
  const dep = depMap.get(key);
  if (dep) {
    dep.forEach((effect) => {
      effect();
    });
  }
}



// ------>下面开始的是模块4的部分
// 声明代理对象描述符
const handler: BasicHandler = {
  get(target: any, key: string | number, receiver) {
    let res = Reflect.get(target, key, receiver);
    track(targetMap, target, key); // 注意：在这里收集追踪依赖！！
    return res;
  },
  set(target: any, key: string | number, value: any, receiver) {
    let previousValue = target[key]; // 旧值
    let res: boolean = Reflect.set(target, key, value, receiver); // 注意先后顺序，先反射再检测值是否需要触发更新
    // 当侦听到新值与旧值不等时，触发更新
    if (previousValue !== value) {
      trigger(targetMap, target, key); // 注意：在这里更新收集到的依赖
    }
    return res; // 正常设置反射
  },
};
// 返回响应式代理对象
function reactive(target: any) {
  return new Proxy(target, handler);
}



// 测试用例4
let goods = {
  price: 10,
  quantity: 5,
};
let proxyGoods = reactive(goods); // 现在proxyGoods变成了响应式的对象！
let total = 0;
let effect = () => {
  total = proxyGoods.price * proxyGoods.quantity;
};
effect(); // 收集到了proxyGoods的依赖，相当于Vue 2中的touch
log(total); // 50
proxyGoods.price = 100;
log(total); // 500
proxyGoods.quantity = 10;
log(total); // 1000
proxyGoods.quantity = 20;
log(total); // 2000
// 现在你可以发现数据是响应式的了，
// proxyGoods的属性变化，都将触发依赖函数effect的运行，而且这些操作是自动的
